package service

import (
	"fmt"
	"log"
	"mini-gde/client"
	"mini-gde/model"
	"os"
	"os/exec"
	"time"

	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/util/homedir"
)

func HelmPackageApps(app string) error {
	path := homedir.HomeDir() + "/tmp/apps/" + app
	fmt.Println(path)
	os.Chdir(path)
	cmd := exec.Command("helm", "package", "package")
	err := cmd.Run()

	if err != nil {
		// 命令执行失败
		panic(err)
	}
	return nil
}

func HelmInstallApps(app string) error {
	path := homedir.HomeDir() + "/tmp/apps/" + app
	fmt.Println(path)
	os.Chdir(path)
	cmd := exec.Command("helm",
		"install", app, app+"-0.1.0.tgz")
	//// 执行命令，返回命令是否执行成功
	//helm install learn-api learn-api-0.1.0.tgz
	err := cmd.Run()

	if err != nil {
		// 命令执行失败
		// err2 := HelmUpgradeApps(app)
		// panic(err)
		// if err2 != nil {
		panic(err)
		// }
	}
	return nil
}
func HelmRestartApps(app string) error {
	cli := client.Clientset
	fmt.Println(app)
	clientset := cli
	deployment, err := cli.AppsV1().Deployments("default").Get(client.Ctx, app, metav1.GetOptions{})
	if err != nil {
		panic(err.Error())
	}
	if errors.IsNotFound(err) {
		log.Printf("Deployment not found\n")
	} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
		log.Printf("Error getting deployment%v\n", statusError.ErrStatus.Message)
	} else if err != nil {
		panic(err.Error())
	} else {
		log.Printf("Found deployment\n")
		name := deployment.GetName()
		log.Printf("name ->", name)
		containers := &deployment.Spec.Template.Spec.Containers
		for i := range *containers {
			c := *containers
			log.Printf("Old image ->", c[i].Image)
		}

	}
	data := fmt.Sprintf(`{"spec":{"template":{"metadata":{"annotations":{"kubectl.kubernetes.io/restartedAt":"%s"}}}}}`, time.Now().String())
	_, err2 := clientset.AppsV1().Deployments("default").Patch(client.Ctx, deployment.Name, types.StrategicMergePatchType, []byte(data), metav1.PatchOptions{FieldManager: "kubectl-rollout"})
	if err2 != nil {
		panic(err2.Error())
	}
	return nil
}
func HelmUpgradeApps(app string) error {
	path := homedir.HomeDir() + "/tmp/apps/" + app
	fmt.Println(path)
	os.Chdir(path)
	cmd := exec.Command("helm",
		"upgrade", app, app+"-0.1.0.tgz")
	//// 执行命令，返回命令是否执行成功
	//helm upgrade learn-api learn-api-0.1.0.tgz
	err := cmd.Run()

	if err != nil {
		// 命令执行失败
		panic(err)
	}
	return nil
}
func HelmListApps() []model.HelmApp {
	log.SetFlags(log.Lshortfile | log.Ldate | log.Lmicroseconds)
	cli := client.Clientset
	deployments, err := cli.AppsV1().Deployments("default").List(client.Ctx, metav1.ListOptions{})
	if err != nil {
		panic(err)
	}
	for idx, deploy := range deployments.Items {
		//fmt.Printf("%d -> %s\n", idx+1, deploy.Name)
		log.Printf("%d -> %s\n", idx+1, deploy.Name)
	}
	//1、获取default下pod的名字
	ctx := client.Ctx
	clientset := cli
	pods, err := cli.CoreV1().Pods("default").List(ctx, metav1.ListOptions{})
	if err != nil {
		// handle error
		log.Printf("error %s, while listing all the pods from default namespace\n", err.Error())
	}

	//在k8s源码当中https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/api/core/v1/types.go
	//type PodList struct 定义了podlist ,Items []Pod定义了包含切片Pod的项目
	//metav1.TypeMeta `json:",inline"`
	// Standard list metadata.
	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
	// +optional
	//metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	// List of pods.
	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md
	//Items []Pod `json:"items" protobuf:"bytes,2,rep,name=items"`

	//所以我们就可以之间使用for循环取出此切片的长度了
	for _, pod := range pods.Items {
		log.Printf("%s", pod.Name)
	}

	fmt.Println("获取default namespace下的deployment的名字 ")
	//2、获取default下deployment的资源名字
	deployments1, err := cli.AppsV1().Deployments("default").List(ctx, metav1.ListOptions{})
	if err != nil {
		log.Printf("listing deployments %s", err.Error())
	}
	for _, d := range deployments1.Items {
		log.Printf("%s\n", d.Name)

	}

	fmt.Println("获取kube-system namespace下的daemonset的名字 ")
	//3、获取kube-system下daemonset的资源名字
	daemonsets, err := clientset.AppsV1().DaemonSets("kube-system").List(ctx, metav1.ListOptions{})
	if err != nil {
		log.Printf("listing daemonsets %s", err.Error())
	}
	for _, ds := range daemonsets.Items {
		log.Printf("%s", ds.Name)
	}

	fmt.Println("获取get node的方法 ")
	//4、获取get node的的名字
	node, err := clientset.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
	if err != nil {
		log.Printf("listing Node %s\n", err.Error())
	}
	for _, no := range node.Items {
		log.Printf("%s\n", no.Name)
	}

	fmt.Println("获取kube-system svc")
	//5、获取kube-system下的service
	svc, err := clientset.CoreV1().Services("kube-system").List(ctx, metav1.ListOptions{})
	if err != nil {
		log.Printf("listing service %s\n", err.Error())
	}
	for _, service := range svc.Items {
		log.Printf("%s\n", service.Name)
	}

	result := make([]model.HelmApp, 0, len(deployments.Items))
	for _, deployment := range deployments.Items {
		//fmt.Printf(string(deployment.Status.Conditions[0].Status) + "\n")
		tmp := model.HelmApp{
			Names:        deployment.Name,
			NameSpace:    deployment.Namespace,
			Image:        abc(deployment.Name),
			UpdateStatus: string(deployment.Status.Conditions[0].Status),
			CreateTime:   deployment.CreationTimestamp.Format("2006-01-02 15:04:05"),
			Labels:       deployment.Labels,
		}
		result = append(result, tmp)
	}
	return result
}
func abc(deploymentName string) string {
	cli := client.Clientset
	deployment, err := cli.AppsV1().Deployments("default").Get(client.Ctx, deploymentName, metav1.GetOptions{})
	if err != nil {
		panic(err.Error())
	}
	if errors.IsNotFound(err) {
		log.Printf("Deployment not found\n")
	} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
		log.Printf("Error getting deployment%v\n", statusError.ErrStatus.Message)
	} else if err != nil {
		panic(err.Error())
	} else {
		log.Printf("Found deployment\n")
		name := deployment.GetName()
		log.Printf("name ->", name)
		containers := &deployment.Spec.Template.Spec.Containers
		for i := range *containers {
			c := *containers
			log.Printf("Old image ->", c[i].Image)
			return c[i].Image
		}

	}
	return ""
}
